"""
@author: 江同学呀
@file: full_text_queries.py
@date: 2025/1/12 14:46
@desc:
    全文查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/full-text-queries.html

    The full text queries enable you to search analyzed text fields such as the body of an email. The query string is
    processed using the same analyzer that was applied to the field during indexing.
    通过全文查询，您可以搜索分析的文本字段，例如电子邮件的正文。查询字符串使用在索引期间应用于字段的相同分析器进行处理。
"""
from typing import Union, Dict, Iterable, Type, Literal

from espc.common.common import Number
from espc.common.query_common import Rewrite, Operator, ZeroTermsQuery, MultiMatchType, OperatorFlag
from espc.orm.model.dsl.queries.base_queries import _BaseQueries
from espc.orm.model.struct.intervals_rule import IntervalsRule, FilterRule, MatchRule, PrefixRule, WildcardRule, \
    FuzzyRule, AllOfRule, AnyOfRule
from espc.orm.model.mapping.field.base_field.base_field import _BaseField
from espc.orm.model.text_analysis.analyzer import BaseAnalyzer


class Intervals(_BaseQueries):
    """
    区间查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-intervals-query.html

    Returns documents based on the order and proximity of matching terms.
    The intervals query uses matching rules, constructed from a small set of definitions. These rules are then applied
    to terms from a specified field.
    The definitions produce sequences of minimal intervals that span terms in a body of text. These intervals can be
    further combined and filtered by parent sources.

    根据匹配词的顺序和接近度返回文档。
    intervals 查询使用匹配规则，这些规则由一小组定义构成。然后，这些规则将应用于指定字段中的术语。
    这些定义生成跨文本正文中术语的最小间隔序列。这些间隔可以进一步组合并按父源进行筛选。

    :param field:
        (Required, rule object) Field you wish to search.
        The value of this parameter is a rule object used to match documents based on matching terms, order, and proximity.
        Valid rules include:
            - match
            - prefix
            - wildcard
            - fuzzy
            - all_of
            - any_of

        （必需，规则对象）要搜索的字段。
        此参数的值是一个规则对象，用于根据匹配的词、顺序和邻近度来匹配文档。
        有效规则包括：
            - match
            - prefix
            - wildcard
            - fuzzy
            - all_of
            - any_of
    :param rule:
    """
    type: str = "intervals"

    def __init__(self, field: Union[str, _BaseField], rule: Union[Dict, IntervalsRule]):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._rule: Union[Dict, IntervalsRule] = rule
        return

    def _build(self) -> Dict:
        return {
            (
                self._field
                if isinstance(self._field, str)
                else (self._field._field_name_path or self._field._field_name)
            ): self._rule if isinstance(self._rule, Dict) else self._rule._build()
        }


class Match(_BaseQueries):
    """
    匹配查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-match-query.html

    Returns documents that match a provided text, number, date or boolean value. The provided text is analyzed before matching.
    The match query is the standard query for performing a full-text search, including options for fuzzy matching.

    返回与提供的文本、数字、日期或布尔值匹配的文档。在匹配之前，将分析提供的文本。
    match 查询是执行全文搜索的标准查询，包括模糊匹配的选项。

    :param field:
    :param query:
        (Required) Text, number, boolean value or date you wish to find in the provided <field>.
        The match query analyzes any provided text before performing a search. This means the match query can search
        text fields for analyzed tokens rather than an exact term.

        （必填）您希望在提供的 <field> 中找到的文本、数字、布尔值或日期。
        match 查询在执行搜索之前分析提供的任何文本。这意味着匹配查询可以在文本字段中搜索已分析的标记，而不是确切的术语。
    :param analyzer:
        (Optional, string) Analyzer used to convert the text in the query value into tokens. Defaults to the index-time
        analyzer mapped for the <field>. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）Analyzer 用于将查询值中的文本转换为标记。默认为为 <field> 映射的索引时间分析器。如果未映射 analyzer，
        则使用索引的默认 analyzer。
    :param auto_generate_synonyms_phrase_query:
        (Optional, Boolean) If true, match phrase queries are automatically created for multi-term synonyms.
        Defaults to true.
        See Use synonyms with match query for an example.

        （可选，布尔值）如果为 true，则会自动为多词词同义词创建匹配短语查询。默认为 true。
        有关示例，请参阅将同义词与 match query 一起使用。
    :param fuzziness:
        (Optional, string) Maximum edit distance allowed for matching. See Fuzziness for valid values and more
        information. See Fuzziness in the match query for an example.
        （可选，字符串）允许匹配的最大编辑距离。请参阅 Fuzziness 了解有效值和更多信息。有关示例，请参阅 Fuzziness in the match query 。
    :param max_expansions:
        (Optional, integer) Maximum number of terms to which the query will expand. Defaults to 50.
        （可选，整数）查询将扩展到的最大字词数。默认值为 50。
    :param prefix_length:
        (Optional, integer) Number of beginning characters left unchanged for fuzzy matching. Defaults to 0.
        （可选，整数）模糊匹配保持不变的开始字符数。默认为 0。
    :param fuzzy_transpositions:
        (Optional, Boolean) If true, edits for fuzzy matching include transpositions of two adjacent characters
        (ab → ba). Defaults to true.
        （可选，布尔值）如果为 true，则模糊匹配的编辑包括两个相邻字符 （ab → ba） 的换位。默认为 true。
    :param fuzzy_rewrite:
        (Optional, string) Method used to rewrite the query. See the rewrite parameter for valid values and more
        information.
        If the fuzziness parameter is not 0, the match query uses a fuzzy_rewrite method of
        top_terms_blended_freqs_${max_expansions} by default.

        （可选，字符串）用于重写查询的方法。请参阅 rewrite 参数 以获取有效值和更多信息。
        如果 fuzziness 参数不为 0，则匹配查询默认使用 fuzzy_rewrite top_terms_blended_freqs_${max_expansions} 方法。
    :param lenient:
        (Optional, Boolean) If true, format-based errors, such as providing a text query value for a numeric field, are
        ignored. Defaults to false.
        （可选，布尔值）如果为 true，则忽略基于格式的错误，例如为数值字段提供文本查询值。默认为 false。
    :param operator:
        (Optional, string) Boolean logic used to interpret text in the query value. Valid values are:
        OR (Default)
            For example, a query value of capital of Hungary is interpreted as capital
            OR of OR Hungary.
        AND
            For example, a query value of capital of Hungary is interpreted as capital
            AND of AND Hungary.

        （可选，字符串）用于解释查询值中的文本的布尔逻辑。有效值为：
        OR （默认）
            例如，查询 capital of Hungary 被解释为 capital 或 of 或 Hungary。
        AND
            例如，查询 capital of Hungary 被解释为 capital 且 of 且 Hungary。
    :param minimum_should_match:
        (Optional, string) Minimum number of clauses that must match for a document to be returned. See the
        minimum_should_match parameter for valid values and more information.
        （可选，字符串）返回文档必须匹配的最小子句数。请参阅 minimum_should_match 参数 了解有效值和更多信息。
    :param zero_terms_query:
        (Optional, string) Indicates whether no documents are returned if the analyzer removes all tokens, such as when
        using a stop filter. Valid values are:
        - none (Default)
            No documents are returned if the analyzer removes all tokens.
        - all
            Returns all documents, similar to a match_all query.
        See Zero terms query for an example.

        （可选，字符串）指示如果分析器删除所有标记（例如使用停止筛选器时），是否不返回任何文档。有效值为：
        - none （默认）
            如果分析器删除所有标记，则不会返回任何文档。
        - all
            返回所有文档，类似于 match_all 查询。
        有关示例，请参阅 零项查询。
    :param cutoff_frequency:
        Deprecated in 7.3.0.
        This option can be omitted as the Match can skip blocks of documents efficiently, without any configuration,
        provided that the total number of hits is not tracked.
        The match query supports a cutoff_frequency that allows specifying an absolute or relative document frequency
        where high frequency terms are moved into an optional subquery and are only scored if one of the low frequency
        (below the cutoff) terms in the case of an or operator or all of the low frequency terms in the case of an and
        operator match.
        This query allows handling stopwords dynamically at runtime, is domain independent and doesn’t require a
        stopword file. It prevents scoring / iterating high frequency terms and only takes the terms into account if a
        more significant / lower frequency term matches a document. Yet, if all of the query terms are above the given
        cutoff_frequency the query is automatically transformed into a pure conjunction (and) query to ensure fast
        execution.
        The cutoff_frequency can either be relative to the total number of documents if in the range from 0 (inclusive)
        to 1 (exclusive) or absolute if greater or equal to 1.0.

        在 7.3.0 中已弃用。
        此选项可以省略，因为 Match 可以有效地跳过文档块，而无需任何配置，前提是不跟踪点击总数。
        match 查询支持一个cutoff_frequency，该 允许指定绝对或相对文档频率，其中高频词被移动到可选的子查询中，并且只有在 or 运算符的情况下
        是低频（低于截止）词之一时，或者在 and 运算符匹配的情况下，只有当所有低频词时才进行评分。
        此查询允许在运行时动态处理停用词，与域无关，不需要停用词文件。它可以防止对高频词进行评分/迭代，并且仅在更重要/较低频率的词与文档匹配时才
        考虑这些词。但是，如果所有查询词都高于给定cutoff_frequency则查询会自动转换为纯连接（和）查询，以确保快速执行。
        如果 cutoff_frequency 在 0（含）到 1（不包括）的范围内，则可以是相对于文档总数的，如果大于或等于 1.0，则可以是绝对的。
    """
    type: str = "match"

    def __init__(
            self, field: Union[str, _BaseField], query: str = None, value: str = None, analyzer: Union[str, BaseAnalyzer] = None,
            auto_generate_synonyms_phrase_query: bool = None, fuzziness: str = None, max_expansions: int = None,
            prefix_length: int = None, fuzzy_transpositions: bool = None, fuzzy_rewrite: Union[str, Rewrite] = None,
            lenient: bool = None, operator: Union[Literal["AND", "OR"], Operator] = None,
            minimum_should_match: Union[str, int] = None, zero_terms_query: Union[str, ZeroTermsQuery] = None,
            cutoff_frequency: Number = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._query: str = query
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._auto_generate_synonyms_phrase_query: bool = auto_generate_synonyms_phrase_query
        self._fuzziness: str = fuzziness
        self._max_expansions: int = max_expansions
        self._prefix_length: int = prefix_length
        self._fuzzy_transpositions: bool = fuzzy_transpositions
        self._fuzzy_rewrite: Union[str, Rewrite] = fuzzy_rewrite
        self._lenient: bool = lenient
        self._operator: Union[Literal["AND", "OR"], Operator, None] = operator
        self._minimum_should_match: Union[str, int] = minimum_should_match
        self._zero_terms_query: Union[str, ZeroTermsQuery] = zero_terms_query
        self._cutoff_frequency: Number = cutoff_frequency
        return

    def _build(self) -> Dict:
        if (
                not self._analyzer and not self._auto_generate_synonyms_phrase_query and not self._fuzziness
                and not self._max_expansions and not self._prefix_length and not self._fuzzy_transpositions
                and not self._fuzzy_rewrite and not self._lenient and not self._operator
                and not self._minimum_should_match and not self._zero_terms_query and not self._cutoff_frequency
        ):
            return {
                (
                    self._field
                    if isinstance(self._field, str)
                    else (self._field._field_name_path or self._field._field_name)
                ): self._query
            }
        _body: Dict = {
            "query": self._query
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._auto_generate_synonyms_phrase_query is not None:
            _body["auto_generate_synonyms_phrase_query"] = self._auto_generate_synonyms_phrase_query
        if self._fuzziness:
            _body["fuzziness"] = self._fuzziness
        if self._max_expansions is not None:
            _body["max_expansions"] = self._max_expansions
        if self._prefix_length is not None:
            _body["prefix_length"] = self._prefix_length
        if self._fuzzy_transpositions is not None:
            _body["fuzzy_transpositions"] = self._fuzzy_transpositions
        if self._fuzzy_rewrite:
            _body["fuzzy_rewrite"] = (
                self._fuzzy_rewrite if isinstance(self._fuzzy_rewrite, str) else self._fuzzy_rewrite.value
            )
        if self._lenient is not None:
            _body["lenient"] = self._lenient
        if self._operator:
            _body["operator"] = (self._operator if isinstance(self._operator, str) else self._operator.value)
        if self._minimum_should_match is not None:
            _body["minimum_should_match"] = self._minimum_should_match
        if self._zero_terms_query:
            _body["zero_terms_query"] = (
                self._zero_terms_query if isinstance(self._zero_terms_query, str) else self._zero_terms_query.value
            )
        if self._cutoff_frequency is not None:
            _body["cutoff_frequency"] = self._cutoff_frequency
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class MatchBooleanPrefix(Match):
    """
    匹配布尔前缀查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-match-bool-prefix-query.html

    A match_bool_prefix query analyzes its input and constructs a bool query from the terms. Each term except the last
    is used in a term query. The last term is used in a prefix query.
    match_bool_prefix 查询分析其输入，并根据字词构造 bool 查询。除最后一个术语外，每个术语都在术语查询中使用。最后一个词用于前缀查询。

    :param field:
    :param query:
        (Required) Text, number, boolean value or date you wish to find in the provided <field>.
        The match query analyzes any provided text before performing a search. This means the match query can search
        text fields for analyzed tokens rather than an exact term.

        （必填）您希望在提供的 <field> 中找到的文本、数字、布尔值或日期。
        match 查询在执行搜索之前分析提供的任何文本。这意味着匹配查询可以在文本字段中搜索已分析的标记，而不是确切的术语。
    :param analyzer:
        (Optional, string) Analyzer used to convert the text in the query value into tokens. Defaults to the index-time
        analyzer mapped for the <field>. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）Analyzer 用于将查询值中的文本转换为标记。默认为为 <field> 映射的索引时间分析器。如果未映射 analyzer，
        则使用索引的默认 analyzer。
    :param fuzziness:
        (Optional, string) Maximum edit distance allowed for matching. See Fuzziness for valid values and more
        information. See Fuzziness in the match query for an example.
        （可选，字符串）允许匹配的最大编辑距离。请参阅 Fuzziness 了解有效值和更多信息。有关示例，请参阅 Fuzziness in the match query 。
    :param max_expansions:
        (Optional, integer) Maximum number of terms to which the query will expand. Defaults to 50.
        （可选，整数）查询将扩展到的最大字词数。默认值为 50。
    :param prefix_length:
        (Optional, integer) Number of beginning characters left unchanged for fuzzy matching. Defaults to 0.
        （可选，整数）模糊匹配保持不变的开始字符数。默认为 0。
    :param fuzzy_transpositions:
        (Optional, Boolean) If true, edits for fuzzy matching include transpositions of two adjacent characters
        (ab → ba). Defaults to true.
        （可选，布尔值）如果为 true，则模糊匹配的编辑包括两个相邻字符 （ab → ba） 的换位。默认为 true。
    :param fuzzy_rewrite:
        (Optional, string) Method used to rewrite the query. See the rewrite parameter for valid values and more
        information.
        If the fuzziness parameter is not 0, the match query uses a fuzzy_rewrite method of
        top_terms_blended_freqs_${max_expansions} by default.

        （可选，字符串）用于重写查询的方法。请参阅 rewrite 参数 以获取有效值和更多信息。
        如果 fuzziness 参数不为 0，则匹配查询默认使用 fuzzy_rewrite top_terms_blended_freqs_${max_expansions} 方法。
    :param operator:
        (Optional, string) Boolean logic used to interpret text in the query value. Valid values are:
        OR (Default)
            For example, a query value of capital of Hungary is interpreted as capital OR of OR Hungary.
        AND
            For example, a query value of capital of Hungary is interpreted as capital AND of AND Hungary.

        （可选，字符串）用于解释查询值中的文本的布尔逻辑。有效值为：
        OR （默认）
            例如，查询 capital of Hungary 被解释为 capital 或 of 或 Hungary。
        AND
            例如，查询 capital of Hungary 被解释为 capital 且 of 且 Hungary。
    :param minimum_should_match:
        (Optional, string) Minimum number of clauses that must match for a document to be returned. See the
        minimum_should_match parameter for valid values and more information.
        （可选，字符串）返回文档必须匹配的最小子句数。请参阅 minimum_should_match 参数 了解有效值和更多信息。
    """
    type: str = "match_bool_prefix"

    def __init__(
            self, field: Union[str, _BaseField], query: str = None, value: str = None, analyzer: Union[str, BaseAnalyzer] = None,
            fuzziness: str = None, max_expansions: int = None, prefix_length: int = None,
            fuzzy_transpositions: bool = None, fuzzy_rewrite: Union[str, Rewrite] = None,
            operator: Union[Literal["AND", "OR"], Operator] = None, minimum_should_match: Union[str, int] = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__(
            field=field, query=query, analyzer=analyzer, fuzziness=fuzziness, max_expansions=max_expansions,
            prefix_length=prefix_length, fuzzy_transpositions=fuzzy_transpositions, fuzzy_rewrite=fuzzy_rewrite,
            operator=operator, minimum_should_match=minimum_should_match
        )
        return

    def _build(self) -> Dict:
        if (
                not self._analyzer and not self._fuzziness and not self._max_expansions and not self._prefix_length
                and not self._fuzzy_transpositions and not self._fuzzy_rewrite and not self._operator
                and not self._minimum_should_match
        ):
            return {
                (
                    self._field
                    if isinstance(self._field, str)
                    else (self._field._field_name_path or self._field._field_name)
                ): self._query
            }
        _body: Dict = {
            "query": self._query
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._fuzziness:
            _body["fuzziness"] = self._fuzziness
        if self._max_expansions is not None:
            _body["max_expansions"] = self._max_expansions
        if self._prefix_length is not None:
            _body["prefix_length"] = self._prefix_length
        if self._fuzzy_transpositions is not None:
            _body["fuzzy_transpositions"] = self._fuzzy_transpositions
        if self._fuzzy_rewrite:
            _body["fuzzy_rewrite"] = (
                self._fuzzy_rewrite if isinstance(self._fuzzy_rewrite, str) else self._fuzzy_rewrite.value
            )
        if self._operator:
            _body["operator"] = (self._operator if isinstance(self._operator, str) else self._operator.value)
        if self._minimum_should_match is not None:
            _body["minimum_should_match"] = self._minimum_should_match
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class MatchPhrase(Match):
    """
    匹配短语查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-match-query-phrase.html

    The match_phrase query analyzes the text and creates a phrase query out of the analyzed text.
    match_phrase 查询分析文本并从分析的文本中创建短语查询。

    :param field:
    :param query:
        (Required) Text, number, boolean value or date you wish to find in the provided <field>.
        The match query analyzes any provided text before performing a search. This means the match query can search
        text fields for analyzed tokens rather than an exact term.

        （必填）您希望在提供的 <field> 中找到的文本、数字、布尔值或日期。
        match 查询在执行搜索之前分析提供的任何文本。这意味着匹配查询可以在文本字段中搜索已分析的标记，而不是确切的术语。
    :param analyzer:
        (Optional, string) Analyzer used to convert the text in the query value into tokens. Defaults to the index-time
        analyzer mapped for the <field>. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）Analyzer 用于将查询值中的文本转换为标记。默认为为 <field> 映射的索引时间分析器。如果未映射 analyzer，
        则使用索引的默认 analyzer。
    :param zero_terms_query:
        (Optional, string) Indicates whether no documents are returned if the analyzer removes all tokens, such as when
        using a stop filter. Valid values are:
        - none (Default)
            No documents are returned if the analyzer removes all tokens.
        - all
            Returns all documents, similar to a match_all query.
        See Zero terms query for an example.

        （可选，字符串）指示如果分析器删除所有标记（例如使用停止筛选器时），是否不返回任何文档。有效值为：
        - none （默认）
            如果分析器删除所有标记，则不会返回任何文档。
        - all
            返回所有文档，类似于 match_all 查询。
        有关示例，请参阅 零项查询。
    """
    type: str = "match_phrase"

    def __init__(
            self, field: Union[str, _BaseField], query: str = None, value: str = None,
            analyzer: Union[str, BaseAnalyzer] = None, zero_terms_query: Union[str, ZeroTermsQuery] = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__(field=field, query=query or value, analyzer=analyzer, zero_terms_query=zero_terms_query)
        return

    def _build(self) -> Dict:
        if (
                not self._analyzer and not self._zero_terms_query
        ):
            return {
                (
                    self._field
                    if isinstance(self._field, str)
                    else (self._field._field_name_path or self._field._field_name)
                ): self._query
            }
        _body: Dict = {
            "query": self._query
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._zero_terms_query:
            _body["zero_terms_query"] = (
                self._zero_terms_query if isinstance(self._zero_terms_query, str) else self._zero_terms_query.value
            )
        return {
            (
                self._field
                if isinstance(self._field, str)
                else (self._field._field_name_path or self._field._field_name)
            ): _body
        }


class MatchPhrasePrefix(Match):
    """
    匹配短语前缀查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-match-query-phrase-prefix.html

    Returns documents that contain the words of a provided text, in the same order as provided. The last term of the
    provided text is treated as a prefix, matching any words that begin with that term.
    按提供的顺序返回包含所提供文本的单词的文档。所提供文本的最后一个词被视为前缀，匹配以该词开头的任何单词。

    :param field:
    :param query:
        (Required, string) Text you wish to find in the provided <field>.
        The match_phrase_prefix query analyzes any provided text into tokens before performing a search. The last term
        of this text is treated as a prefix, matching any words that begin with that term.

        （必需，字符串）您希望在提供的 <field> 中找到的文本。
        match_phrase_prefix 查询在执行搜索之前将提供的任何文本分析为标记。此文本的最后一个词被视为前缀，匹配以该词开头的任何单词。
    :param analyzer:
        (Optional, string) Analyzer used to convert text in the query value into tokens. Defaults to the index-time
        analyzer mapped for the <field>. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）用于将查询值中的文本转换为标记的分析器。默认为为 <field> 映射的索引时间分析器。如果未映射 analyzer，
        则使用索引的默认 analyzer。
    :param max_expansions:
        (Optional, integer) Maximum number of terms to which the last provided term of the query value will expand.
        Defaults to 50.
        （可选，整数）查询值的最后提供的术语将扩展到的最大术语数。默认值为 50。
    :param slop:
        (Optional, integer) Maximum number of positions allowed between matching tokens. Defaults to 0. Transposed terms
        have a slop of 2.
        （可选，整数）匹配令牌之间允许的最大位置数。默认为 0。转置项的斜率为 2。
    :param zero_terms_query:
        (Optional, string) Indicates whether no documents are returned if the analyzer removes all tokens, such as when
        using a stop filter. Valid values are:
        - none (Default)
            No documents are returned if the analyzer removes all tokens.
        - all
            Returns all documents, similar to a match_all query.

        （可选，字符串）指示如果分析器删除所有标记（例如使用停止筛选器时），是否不返回任何文档。有效值为：
        - none （默认）
            如果分析器删除所有标记，则不会返回任何文档。
        - all
            返回所有文档，类似于 match_all 查询。
    """
    def __init__(
            self, field: Union[str, _BaseField], query: str = None, value: str = None, analyzer: Union[str, BaseAnalyzer] = None,
            max_expansions: int = None, slop: int = None, zero_terms_query: Union[str, ZeroTermsQuery] = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__(
            field=field, query=query, analyzer=analyzer, max_expansions=max_expansions,
            zero_terms_query=zero_terms_query
        )
        self._slop: int = slop
        return

    def _build(self) -> Dict:
        if (
                not self._analyzer and not self._max_expansions and not self._slop and not self._zero_terms_query
        ):
            return {self._field if isinstance(self._field, str) else self._field._field_name: self._query}
        _body: Dict = {
            "query": self._query
        }
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._max_expansions is not None:
            _body["max_expansions"] = self._max_expansions
        if self._slop is not None:
            _body["slop"] = self._slop
        if self._zero_terms_query:
            _body["zero_terms_query"] = (
                self._zero_terms_query if isinstance(self._zero_terms_query, str) else self._zero_terms_query.value
            )
        return {
            (
                self._field
                if isinstance(self._field, str)
                else (self._field._field_name_path or self._field._field_name)
            ): _body
        }


class MultiMatch(_BaseQueries):
    """
    多重匹配查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-multi-match-query.html

    The multi_match query builds on the match query to allow multi-field queries.
    multi_match 查询基于 match 查询构建，以允许多字段查询。

    :param fields:
    :param query:
    :param type_:
    :param tie_breaker:
    :param operator:
    """
    type_: str = "multi_match"

    def __init__(
            self, fields: Iterable[Union[str, _BaseField]], query: str = None, value: str = None,
            type_: Union[
                Literal[
                    "best_fields", "most_fields", "cross_fields", "phrase", "phrase_prefix", "bool_prefix"
                ],
                MultiMatchType
            ] = None, tie_breaker: Number = None, operator: Union[Literal["AND", "OR"], Operator] = None,
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__()
        self._fields: Iterable[Union[str, _BaseField]] = fields
        self._query: str = query
        self._type: Union[
            Literal[
                "best_fields", "most_fields", "cross_fields", "phrase", "phrase_prefix", "bool_prefix"
            ],
            MultiMatchType,
            None
        ] = type_
        self._tie_breaker: Number = tie_breaker
        self._operator: Union[Literal["AND", "OR"], Operator, None] = operator
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "query": self._query,
            "fields": [
                field if isinstance(field, str) else (field._field_name_path or field._field_name)
                for field in self._fields
            ]
        }
        if self._type:
            _body["type"] = (
                self._type if isinstance(self._type, str) else self._type.value
            )
        if self._tie_breaker is not None:
            _body["tie_breaker"] = self._tie_breaker
        if self._operator:
            _body["operator"] = (
                self._operator if isinstance(self._operator, str) else self._operator.value
            )
        return _body


class Combined(_BaseQueries):
    """
    组合字段
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-combined-fields-query.html

    The combined_fields query supports searching multiple text fields as if their contents had been indexed into one
    combined field. The query takes a term-centric view of the input string: first it analyzes the query string into
    individual terms, then looks for each term in any of the fields. This query is particularly useful when a match
    could span multiple text fields, for example the title, abstract, and body of an article.
    combined_fields 查询支持搜索多个文本字段，就像它们的内容已索引到一个组合字段中一样。该查询采用以字词为中心的输入字符串视图：首先，它将查
    询字符串分析为单个字词，然后在任何字段中查找每个字词。当匹配项可以跨越多个文本字段（例如文章的标题、摘要和正文）时，此查询特别有用。

    :param fields:
        (Required, array of strings) List of fields to search. Field wildcard patterns are allowed. Only text fields
        are supported, and they must all have the same search analyzer.
        （必需，字符串数组）要搜索的字段列表。允许使用字段通配符模式。仅支持文本字段，并且它们必须具有相同的搜索分析器。
    :param query:
        (Required, string) Text to search for in the provided <fields>.
        The combined_fields query analyzes the provided text before performing a search.

        （必需，字符串）要在提供的 <fields> 中搜索的文本。
        combined_fields 查询在执行搜索之前分析提供的文本。
    :param auto_generate_synonyms_phrase_query:
        (Optional, Boolean) If true, match phrase queries are automatically created for multi-term synonyms.
        Defaults to true.
        See Use synonyms with match query for an example.

        （可选，布尔值）如果为 true，则会自动为多词词同义词创建匹配短语查询。默认为 true。
        有关示例，请参阅将同义词与 match query 一起使用。
    :param operator:
        (Optional, string) Boolean logic used to interpret text in the query value. Valid values are:
        OR (Default)
            For example, a query value of capital of Hungary is interpreted as capital OR of OR Hungary.
        AND
            For example, a query value of capital of Hungary is interpreted as capital AND of AND Hungary.

        （可选，字符串）用于解释查询值中的文本的布尔逻辑。有效值为：
        OR （默认）
            例如，查询 capital of Hungary 被解释为 capital 或 of 或 Hungary。
        AND
            例如，查询 capital of Hungary 被解释为 capital 且 of 且 Hungary。
    :param minimum_should_match:
        (Optional, string) Minimum number of clauses that must match for a document to be returned. See the
        minimum_should_match parameter for valid values and more information.
        （可选，字符串）返回文档必须匹配的最小子句数。请参阅 minimum_should_match 参数 了解有效值和更多信息。
    :param zero_terms_query:
        (Optional, string) Indicates whether no documents are returned if the analyzer removes all tokens, such as when
        using a stop filter. Valid values are:
        - none (Default)
            No documents are returned if the analyzer removes all tokens.
        - all
            Returns all documents, similar to a match_all query.

        （可选，字符串）指示如果分析器删除所有标记（例如使用停止筛选器时），是否不返回任何文档。有效值为：
        - none （默认）
            如果分析器删除所有标记，则不会返回任何文档。
        - all
            返回所有文档，类似于 match_all 查询。
    """
    type: str = "combined_fields"

    def __init__(
            self, fields: Iterable[Union[str, _BaseField]], query: str = None, value: str = None,
            auto_generate_synonyms_phrase_query: bool = None, operator: Union[Literal["AND", "OR"], Operator] = None,
            minimum_should_match: Union[str, int] = None,
            zero_terms_query: Union[Literal["none", "all"], ZeroTermsQuery] = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__()
        self._fields: Iterable[Union[str, _BaseField]] = fields
        self._query: str = query
        self._auto_generate_synonyms_phrase_query: bool = auto_generate_synonyms_phrase_query
        self._operator: Union[Literal["AND", "OR"], Operator, None] = operator
        self._minimum_should_match: Union[str, int] = minimum_should_match
        self._zero_terms_query: Union[Literal["none", "all"], ZeroTermsQuery, None] = zero_terms_query
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "query": self._query,
            "fields": [
                field if isinstance(field, str) else (field._field_name_path or field._field_name)
                for field in self._fields
            ]
        }
        if self._auto_generate_synonyms_phrase_query is not None:
            _body["auto_generate_synonyms_phrase_query"] = self._auto_generate_synonyms_phrase_query
        if self._operator:
            _body["operator"] = (
                self._operator if isinstance(self._operator, str) else self._operator.value
            )
        if self._minimum_should_match is not None:
            _body["minimum_should_match"] = self._minimum_should_match
        if self._zero_terms_query:
            _body["zero_terms_query"] = (
                self._zero_terms_query if isinstance(self._zero_terms_query, str) else self._zero_terms_query.value
            )
        return _body


class QueryString(_BaseQueries):
    """
    查询字符串查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-query-string-query.html

    Returns documents based on a provided query string, using a parser with a strict syntax.
    This query uses a syntax to parse and split the provided query string based on operators, such as AND or NOT. The
    query then analyzes each split text independently before returning matching documents.
    You can use the query_string query to create a complex search that includes wildcard characters, searches across
    multiple fields, and more. While versatile, the query is strict and returns an error if the query string includes
    any invalid syntax.

    使用具有严格语法的解析器，根据提供的查询字符串返回文档。
    此查询使用语法根据运算符（如 AND 或 NOT）解析和拆分提供的查询字符串。然后，查询在返回匹配文档之前独立分析每个拆分文本。
    您可以使用 query_string 查询创建复杂搜索，其中包括通配符、跨多个字段的搜索等。虽然用途广泛，但查询是严格的，如果查询字符串包含任何无效语法，则返回错误。

    :param query:
        (Required, string) Query string you wish to parse and use for search. See Query string syntax.
        （必需，字符串）查询要解析并用于搜索的字符串。请参阅 查询字符串语法。
    :param default_field:
        (Optional, string) Default field to search if no field is provided in the query string. Supports wildcards (*).
        Defaults to the index.query.default_field index setting, which has a default value of *. The * value extracts
        all fields that are eligible for term queries and filters the metadata fields. All extracted fields are then
        combined to build a query if no prefix is specified.
        Searching across all eligible fields does not include nested documents. Use a nested query to search those
        documents.
        For mappings with a large number of fields, searching across all eligible fields could be expensive.
        There is a limit on the number of fields that can be queried at once. It is defined by the
        indices.query.bool.max_clause_count search setting, which defaults to 1024.

        （可选，字符串）默认字段 （Default field） 如果查询字符串中未提供任何字段，则进行搜索。支持通配符 （*）。
        默认为 index.query.default_field 索引设置，其默认值为 *。的 * 值提取符合术语查询条件的所有字段，并筛选元数据字段。如果未指定前缀，
        则合并所有提取的字段以构建查询。
        在所有符合条件的字段中搜索不包括嵌套文档。使用嵌套查询搜索这些文档。
        对于具有大量字段的映射，在所有符合条件的字段中进行搜索可能会很昂贵。
        一次可以查询的字段数量是有限制的。它由 indices.query.bool.max_clause_count 搜索设置定义，默认为 1024。
    :param allow_leading_wildcard:
        (Optional, Boolean) If true, the wildcard characters * and ? are allowed as the first character of the query
        string. Defaults to true.
        （可选，布尔值）如果为 true，则允许将通配符 * 和 ？作为查询字符串的第一个字符。默认为 true。
    :param analyze_wildcard:
        (Optional, Boolean) If true, the query attempts to analyze wildcard terms in the query string. Defaults to false.
        （可选，布尔值）如果为 true，则查询将尝试分析查询字符串中的通配符词。默认为 false。
    :param analyzer:
        (Optional, string) Analyzer used to convert text in the query string into tokens. Defaults to the index-time
        analyzer mapped for the default_field. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）用于将查询字符串中的文本转换为标记的分析器。默认为default_field映射的索引时间分析器。如果未映射 analyzer，则使用索引的默认 analyzer。
    :param auto_generate_synonyms_phrase_query:
        (Optional, Boolean) If true, match phrase queries are automatically created for multi-term synonyms. Defaults
        to true. See Synonyms and the query_string query for an example.
        （可选，布尔值）如果为 true，则会自动为多词词同义词创建匹配短语查询。默认为 true。有关示例，请参阅 同义词 和 query_string 查询。
    :param boost:
        (Optional, float) Floating point number used to decrease or increase the relevance scores of the query.
        Defaults to 1.0.
        Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases the relevance
        score. A value greater than 1.0 increases the relevance score.

        （可选，浮点数）用于降低或增加查询相关性分数的浮点数。默认为 1.0。
        提升值是相对于默认值 1.0 的。介于 0 和 1.0 之间的提升值会降低相关性分数。大于 1.0 的值会增加相关性分数。
    :param default_operator:
        (Optional, string) Default boolean logic used to interpret text in the query string if no operators are
        specified. Valid values are:
        - OR (Default)
            For example, a query string of capital of Hungary is interpreted as capital OR of OR Hungary.
        - AND
            For example, a query string of capital of Hungary is interpreted as capital AND of AND Hungary.

        （可选，字符串）如果未指定运算符，则用于解释查询字符串中的文本的默认布尔逻辑。有效值为：
        - OR （默认）
            例如，匈牙利的 capital 的查询字符串被解释为 capital 或 of 或 匈牙利。
        - AND
            例如，匈牙利的 capital 的查询字符串被解释为 capital 且 的 且 匈牙利。
    :param enable_position_increments:
        (Optional, Boolean) If true, enable position increments in queries constructed from a query_string search.
        Defaults to true.
        （可选，布尔值）如果为 true，则在从 query_string 搜索构建的查询中启用位置增量。默认为 true。
    :param fields:
        (Optional, array of strings) Array of fields to search. Supports wildcards (*).
        You can use this parameter query to search across multiple fields. See Search multiple fields.

        （可选，字符串数组）要搜索的字段数组。支持通配符 （*）。
        您可以使用此参数查询跨多个字段进行搜索。请参阅搜索多个字段。
    :param fuzziness:
        (Optional, string) Maximum edit distance allowed for fuzzy matching. For fuzzy syntax, see Fuzziness.
        （可选，字符串）模糊匹配允许的最大编辑距离。有关模糊语法，请参阅模糊。
    :param fuzzy_max_expansions:
        (Optional, integer) Maximum number of terms to which the query expands for fuzzy matching. Defaults to 50.
        （可选，整数）查询为模糊匹配扩展到的最大字词数。默认值为 50。
    :param fuzzy_prefix_length:
        (Optional, integer) Number of beginning characters left unchanged for fuzzy matching. Defaults to 0.
        （可选，整数）模糊匹配保持不变的开始字符数。默认为 0。
    :param fuzzy_transpositions:
        (Optional, Boolean) If true, edits for fuzzy matching include transpositions of two adjacent characters
        (ab → ba). Defaults to true.
        （可选，布尔值）如果为 true，则模糊匹配的编辑包括两个相邻字符 （ab → ba） 的转置。默认为 true。
    :param lenient:
        (Optional, Boolean) If true, format-based errors, such as providing a text value for a numeric field, are
        ignored. Defaults to false.
        （可选，布尔值）如果为 true，则忽略基于格式的错误，例如为数字字段提供文本值。默认为 false。
    :param max_determinized_states:
        (Optional, integer) Maximum number of automaton states required for the query. Default is 10000.
        Elasticsearch uses Apache Lucene internally to parse regular expressions. Lucene converts each regular
        expression to a finite automaton containing a number of determinized states.
        You can use this parameter to prevent that conversion from unintentionally consuming too many resources.
        You may need to increase this limit to run complex regular expressions.

        （可选，整数）查询所需的最大自动机状态数。默认值为 10000。
        Elasticsearch 在内部使用 Apache Lucene 来解析正则表达式。Lucene 将每个正则表达式转换为包含许多确定状态的有限自动机。
        您可以使用此参数来防止该转换无意中消耗过多资源。您可能需要增加此限制才能运行复杂的正则表达式。
    :param minimum_should_match:
        (Optional, string) Minimum number of clauses that must match for a document to be returned. See the
        minimum_should_match parameter for valid values and more information. See How minimum_should_match works
        for an example.
        （可选，字符串）要返回的文档必须匹配的最小子句数。请参阅 minimum_should_match 参数以获取有效值和更多信息。有关示例，
        请参阅 minimum_should_match的工作原理 。
    :param quote_analyzer:
        (Optional, string) Analyzer used to convert quoted text in the query string into tokens. Defaults to the
        search_quote_analyzer mapped for the default_field.
        For quoted text, this parameter overrides the analyzer specified in the analyzer parameter.

        （可选，字符串）用于将查询字符串中带引号的文本转换为标记的分析器。默认为default_field映射的search_quote_analyzer。
        对于带引号的文本，此参数将覆盖 analyzer 参数中指定的 analyzer。
    :param phrase_slop:
        (Optional, integer) Maximum number of positions allowed between matching tokens for phrases. Defaults to 0.
        If 0, exact phrase matches are required. Transposed terms have a slop of 2.
        （可选，整数）短语的匹配标记之间允许的最大位置数。默认为 0。如果为 0，则需要完全短语匹配。转置术语的斜率为 2。
    :param quote_field_suffix:
        (Optional, string) Suffix appended to quoted text in the query string.
        You can use this suffix to use a different analysis method for exact matches. See Mixing exact search with
        stemming.

        （可选，字符串）附加到查询字符串中带引号的文本的后缀。
        您可以使用此后缀对精确匹配使用不同的分析方法。请参阅将精确搜索与词干混合使用。
    :param rewrite:
        (Optional, string) Method used to rewrite the query. For valid values and more information, see the rewrite
        parameter.
        （可选，字符串）用于重写查询的方法。有关有效值和更多信息，请参阅 rewrite 参数。
    :param time_zone:
        (Optional, string) Coordinated Universal Time (UTC) offset or IANA time zone used to convert date values in the
        query string to UTC.
        Valid values are ISO 8601 UTC offsets, such as +01:00 or -08:00, and IANA time zone IDs, such as
        America/Los_Angeles.

        （可选，字符串）用于将查询字符串中的日期值转换为 UTC 的协调世界时 （UTC） 偏移量或 IANA 时区。
        有效值为 ISO 8601 UTC 偏移量（例如 +01：00 或 -08：00）和 IANA 时区 ID（例如 America/Los_Angeles）。
    """
    type: str = "query_string"

    def __init__(
            self, query: str = None, value: str = None, analyze_wildcard: bool = None, analyzer: Union[str, BaseAnalyzer] = None,
            auto_generate_synonyms_phrase_query: bool = None, boost: float = None,
            default_field: Union[str, _BaseField] = None, default_operator: Union[str, Operator] = None,
            fields: Iterable[Union[str, _BaseField]] = None,  fuzzy_max_expansions: int = None,
            fuzzy_prefix_length: int = None, fuzzy_transpositions: bool = None, lenient: bool = None,
            max_determinized_states: int = None, minimum_should_match: Union[str, int] = None,
            quote_analyzer: Union[str, BaseAnalyzer] = None, phrase_slop: int = None, quote_field_suffix: str = None,
            rewrite: Union[str, Rewrite] = None, time_zone: str = None
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__()
        self._query: str = query
        self._analyze_wildcard: bool = analyze_wildcard
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._auto_generate_synonyms_phrase_query: bool = auto_generate_synonyms_phrase_query
        self._boost: Number = boost
        self._default_field: Union[str, _BaseField] = default_field
        self._default_operator: Union[str, Operator] = default_operator
        self._fields: Iterable[Union[str, _BaseField]] = fields
        self._fuzzy_max_expansions: int = fuzzy_max_expansions
        self._fuzzy_prefix_length: int = fuzzy_prefix_length
        self._fuzzy_transpositions: bool = fuzzy_transpositions
        self._lenient: bool = lenient
        self._max_determinized_states: int = max_determinized_states
        self._minimum_should_match: Union[str, int] = minimum_should_match
        self._quote_analyzer: Union[str, BaseAnalyzer] = quote_analyzer
        self._phrase_slop: int = phrase_slop
        self._quote_field_suffix: str = quote_field_suffix
        self._rewrite: Union[str, Rewrite] = rewrite
        self._time_zone: str = time_zone
        return

    def _build(self) -> Dict:
        """
        构建查询字符串查询
        """
        _body: Dict = {
            "query": self._query,
        }
        if self._analyze_wildcard is not None:
            _body["analyze_wildcard"] = self._analyze_wildcard
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._auto_generate_synonyms_phrase_query is not None:
            _body["auto_generate_synonyms_phrase_query"] = self._auto_generate_synonyms_phrase_query
        if self._boost is not None:
            _body["boost"] = self._boost
        if self._default_field:
            _body["default_field"] = (
                self._default_field if isinstance(self._default_field, str) else self._default_field._field_name
            )
        if self._default_operator:
            _body["default_operator"] = (
                self._default_operator if isinstance(self._default_operator, str) else self._default_operator.value
            )
        if self._fields:
            _body["fields"] = [
                field if isinstance(field, str) else (field._field_name_path or field._field_name)
                for field in self._fields
            ]
        if self._fuzzy_max_expansions is not None:
            _body["fuzzy_max_expansions"] = self._fuzzy_max_expansions
        if self._fuzzy_prefix_length is not None:
            _body["fuzzy_prefix_length"] = self._fuzzy_prefix_length
        if self._fuzzy_transpositions is not None:
            _body["fuzzy_transpositions"] = self._fuzzy_transpositions
        if self._lenient is not None:
            _body["lenient"] = self._lenient
        if self._max_determinized_states is not None:
            _body["max_determinized_states"] = self._max_determinized_states
        if self._minimum_should_match:
            _body["minimum_should_match"] = self._minimum_should_match
        if self._quote_analyzer:
            _body["quote_analyzer"] = (
                self._quote_analyzer if isinstance(self._quote_analyzer, str) else self._quote_analyzer.name
            )
        if self._phrase_slop is not None:
            _body["phrase_slop"] = self._phrase_slop
        if self._quote_field_suffix:
            _body["quote_field_suffix"] = self._quote_field_suffix
        if self._rewrite:
            _body["rewrite"] = self._rewrite if isinstance(self._rewrite, str) else self._rewrite.value
        if self._time_zone:
            _body["time_zone"] = self._time_zone
        return _body


class SimpleQueryString(_BaseQueries):
    """
    简单查询字符串查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-simple-query-string-query.html

    Returns documents based on a provided query string, using a parser with a limited but fault-tolerant syntax.
    This query uses a simple syntax to parse and split the provided query string into terms based on special operators.
    The query then analyzes each term independently before returning matching documents.
    While its syntax is more limited than the query_string query, the simple_query_string query does not return errors
    for invalid syntax. Instead, it ignores any invalid parts of the query string.

    使用具有有限但容错语法的解析器，根据提供的查询字符串返回文档。
    此查询使用简单的语法来解析提供的查询字符串并将其拆分为基于特殊运算符的术语。然后，该查询在返回匹配的文档之前独立分析每个术语。
    虽然 simple_query_string 查询的语法比 query_string 查询更受限制，但 查询不会因语法无效而返回错误。相反，它会忽略查询字符串的任何无效部分。

    :param query:
        (Required, string) Query string you wish to parse and use for search. See Simple query string syntax.
        （必需，字符串）查询要解析并用于搜索的字符串。请参阅简单查询字符串语法。
    :param fields:
        (Optional, array of strings) Array of fields you wish to search.
        This field accepts wildcard expressions. You also can boost relevance scores for matches to particular fields
        using a caret (^) notation. See Wildcards and per-field boosts in the fields parameter for examples.
        Defaults to the index.query.default_field index setting, which has a default value of *. The * value extracts
        all fields that are eligible to term queries and filters the metadata fields. All extracted fields are then
        combined to build a query if no prefix is specified.
        There is a limit on the number of fields that can be queried at once. It is defined by the
        indices.query.bool.max_clause_count search setting, which defaults to 1024.

        （可选，字符串数组）要搜索的字段数组。
        此字段接受通配符表达式。您还可以使用插入符号 （^） 表示法提高与特定字段匹配的相关性分数。有关示例，请参阅 fields 参数中的通配符和每字段提升。
        默认为 index.query.default_field 索引设置，其默认值为 *。的 * 值提取符合术语查询条件的所有字段，并筛选元数据字段。如果未指定前缀，
        则合并所有提取的字段以构建查询。
        一次可以查询的字段数量是有限制的。它由 indices.query.bool.max_clause_count 搜索设置定义，默认为 1024。
    :param default_operator:
        (Optional, string) Default boolean logic used to interpret text in the query string if no operators are
        specified. Valid values are:
        - OR (Default)
            For example, a query string of capital of Hungary is interpreted as capital OR of OR Hungary.
        - AND
            For example, a query string of capital of Hungary is interpreted as capital AND of AND Hungary.

        （可选，字符串）如果未指定运算符，则用于解释查询字符串中的文本的默认布尔逻辑。有效值为：
        - OR （默认）
            例如，匈牙利的 capital 的查询字符串被解释为 capital 或 of 或 匈牙利。
        - AND
            例如，匈牙利的 capital 的查询字符串被解释为 capital 且 的 且 匈牙利。
    :param all_fields:
        [6.0.0] Deprecated in 6.0.0. set fields to * instead
        If true, search all searchable fields in the index’s field mapping.

        在 6.0.0 中已废弃。将 fields 改为 *(Optional, boolean)
        （可选，布尔值）如果为 true，则 搜索索引的字段映射中的所有可搜索字段。
    :param analyze_wildcard:
        (Optional, Boolean) If true, the query attempts to analyze wildcard terms in the query string. Defaults to false.
        （可选，布尔值）如果为 true，则查询将尝试分析查询字符串中的通配符词。默认为 false。
    :param analyzer:
        (Optional, string) Analyzer used to convert text in the query string into tokens. Defaults to the index-time
        analyzer mapped for the default_field. If no analyzer is mapped, the index’s default analyzer is used.
        （可选，字符串）用于将查询字符串中的文本转换为标记的分析器。默认为default_field映射的索引时间分析器。如果未映射 analyzer，
        则使用索引的默认 analyzer。
    :param auto_generate_synonyms_phrase_query:
        (Optional, Boolean) If true, the parser creates a match_phrase query for each multi-position token. Defaults to
        true. For examples, see Multi-position tokens.
        （可选，布尔值）如果为 true，则解析器将为每个多位置令牌创建一个 match_phrase 查询。默认为 true。有关示例，请参阅 多位置令牌。
    :param flags:
        (Optional, string) List of enabled operators for the simple query string syntax. Defaults to ALL (all
        operators). See Limit operators for valid values.
        （可选，字符串）简单查询字符串语法的已启用运算符列表。默认为 ALL （所有运算符）。有关有效值，请参阅限制运算符。
    :param fuzzy_max_expansions:
        (Optional, integer) Maximum number of terms to which the query expands for fuzzy matching. Defaults to 50.
        （可选，整数）查询为模糊匹配扩展到的最大字词数。默认值为 50。
    :param fuzzy_prefix_length:
        (Optional, integer) Number of beginning characters left unchanged for fuzzy matching. Defaults to 0.
        （可选，整数）模糊匹配保持不变的开始字符数。默认为 0。
    :param fuzzy_transpositions:
        (Optional, Boolean) If true, edits for fuzzy matching include transpositions of two adjacent characters
        (ab → ba). Defaults to true.
        （可选，布尔值）如果为 true，则模糊匹配的编辑包括两个相邻字符 （ab → ba） 的转置。默认为 true。
    :param lenient:
        (Optional, Boolean) If true, format-based errors, such as providing a text value for a numeric field, are
        ignored. Defaults to false.
        （可选，布尔值）如果为 true，则忽略基于格式的错误，例如为数值字段提供文本值。默认为 false。
    :param minimum_should_match:
        (Optional, string) Minimum number of clauses that must match for a document to be returned. See the
        minimum_should_match parameter for valid values and more information.
        （可选，字符串）返回文档必须匹配的最小子句数。请参阅 minimum_should_match 参数 了解有效值和更多信息。
    :param quote_field_suffix:
        (Optional, string) Suffix appended to quoted text in the query string.
        You can use this suffix to use a different analysis method for exact matches. See Mixing exact search with
        stemming.

        （可选，字符串）附加到查询字符串中带引号的文本的后缀。
        您可以使用此后缀对完全匹配使用不同的分析方法。请参阅将精确搜索与词干混合使用。
    """
    type: str = "simple_query_string"

    def __init__(
            self, query: str = None, value: str = None, fields: Iterable[Union[str, _BaseField]] = None,
            default_field: Union[str, _BaseField] = None, default_operator: Union[str, Operator] = None,
            all_fields: bool = None, analyze_wildcard: bool = None, analyzer: Union[str, BaseAnalyzer] = None,
            auto_generate_synonyms_phrase_query: bool = None,
            flags: Union[str, OperatorFlag, Iterable[OperatorFlag]] = None, fuzzy_max_expansions: int = None,
            fuzzy_prefix_length: int = None, fuzzy_transpositions: bool = None, lenient: bool = None,
            minimum_should_match: Union[str, int] = None, quote_field_suffix: str = None,
    ):
        if not query and not value:
            raise ValueError("query或value必须设置一个。")
        super().__init__()
        self._query: str = query
        self._fields: Iterable[Union[str, _BaseField]] = fields
        self._default_field: Union[str, _BaseField] = default_field
        self._default_operator: Union[str, Operator] = default_operator
        self._all_fields: bool = all_fields
        self._analyze_wildcard: bool = analyze_wildcard
        self._analyzer: Union[str, BaseAnalyzer] = analyzer
        self._auto_generate_synonyms_phrase_query: bool = auto_generate_synonyms_phrase_query
        self._flags: Union[str, OperatorFlag, Iterable[OperatorFlag]] = flags
        self._fuzzy_max_expansions: int = fuzzy_max_expansions
        self._fuzzy_prefix_length: int = fuzzy_prefix_length
        self._fuzzy_transpositions: bool = fuzzy_transpositions
        self._lenient: bool = lenient
        self._minimum_should_match: Union[str, int] = minimum_should_match
        self._quote_field_suffix: str = quote_field_suffix
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "query": self._query,
        }
        if self._fields:
            _body["fields"] = [
                field if isinstance(field, str) else (field._field_name_path or field._field_name)
                for field in self._fields
            ]
        if self._default_field:
            _body["default_field"] = (
                self._default_field if isinstance(self._default_field, str) else self._default_field._field_name
            )
        if self._default_operator:
            _body["default_operator"] = (
                self._default_operator if isinstance(self._default_operator, str) else self._default_operator.value
            )
        if self._all_fields is not None:
            _body["all_fields"] = self._all_fields
        if self._analyze_wildcard is not None:
            _body["analyze_wildcard"] = self._analyze_wildcard
        if self._analyzer:
            _body["analyzer"] = self._analyzer if isinstance(self._analyzer, str) else self._analyzer.name
        if self._auto_generate_synonyms_phrase_query is not None:
            _body["auto_generate_synonyms_phrase_query"] = self._auto_generate_synonyms_phrase_query
        if self._flags:
            _body["flags"] = (
                self._flags
                if isinstance(self._flags, str)
                else (
                    self._flags.value
                    if isinstance(self._flags, OperatorFlag)
                    else "|".join(flag.value for flag in self._flags)
                )
            )
        if self._fuzzy_max_expansions is not None:
            _body["fuzzy_max_expansions"] = self._fuzzy_max_expansions
        if self._fuzzy_prefix_length is not None:
            _body["fuzzy_prefix_length"] = self._fuzzy_prefix_length
        if self._fuzzy_transpositions is not None:
            _body["fuzzy_transpositions"] = self._fuzzy_transpositions
        if self._lenient is not None:
            _body["lenient"] = self._lenient
        if self._minimum_should_match is not None:
            _body["minimum_should_match"] = self._minimum_should_match
        if self._quote_field_suffix:
            _body["quote_field_suffix"] = self._quote_field_suffix
        return _body





